using ET;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;

namespace Core
{
    public class ThreadTaskComponent : Entity, IAwake, IUpdate
    {
        private int count;
        private int updateTaskMaxCount = 20;
        private bool isRuning = false;
        private Thread thread;
        private readonly ConcurrentQueue<IThreadListener> asyncQueue = new ConcurrentQueue<IThreadListener>();
        private readonly ConcurrentQueue<IThreadListener> nextAsyncQueue = new ConcurrentQueue<IThreadListener>();

        private readonly ConcurrentQueue<IThreadListener> syncQueue = new ConcurrentQueue<IThreadListener>();
        private readonly ConcurrentQueue<IThreadListener> nextSyncQueue = new ConcurrentQueue<IThreadListener>();

        public void AddTask(IThreadListener threadListener)
        {
            if (threadListener == null)
                return;

            asyncQueue.Enqueue(threadListener);
        }

        void IAwake.Awake()
        {
            thread = new Thread(AsyncRun);
            thread.Start();
        }

        void AsyncRun()
        {
            isRuning = true;
            while (isRuning)
            {
                if (!asyncQueue.TryDequeue(out var task))
                {
                    while (nextAsyncQueue.TryDequeue(out task))
                    {
                        asyncQueue.Enqueue(task);
                    }
                    Thread.Sleep(20);
                    continue;
                }

                if (!task.OnAsyncTask())
                {
                    nextAsyncQueue.Enqueue(task);
                }
                else
                {
                    syncQueue.Enqueue(task);
                }

                Thread.Sleep(1);
            }
        }

        void IUpdate.Update()
        {
            count = updateTaskMaxCount;

            while (count-- > 0)
            {
                if (!syncQueue.TryDequeue(out var task))
                {
                    while (nextSyncQueue.TryDequeue(out task))
                    {
                        syncQueue.Enqueue(task);
                    }
                    break;
                };

                if (task.OnSyncTask())
                {
                    task.OnFinally();
                }
                else
                {
                    nextSyncQueue.Enqueue(task);
                }
            }
        }

        public override void Dispose()
        {
            base.Dispose();

            isRuning = false;
            thread?.Join();
            thread = null;
            asyncQueue.Clear();
            nextAsyncQueue.Clear();
            syncQueue.Clear();
            nextSyncQueue.Clear();
        }
    }
}